package edu.kufpg.armatus;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public final class Prefs {
/**
* {@link CheckBoxPreference} key mapping to whether or
* not {@link DeviceConstants#CACHE_DIR CACHE_DIR} should be used to save persistent data (if
* the mapped value is {@code false}). If the mapped value is {@code true}, the String to which
* {@link #HISTORY_DIR_KEY} maps is used instead.
*/
@NonNull static String IS_HISTORY_DIR_CUSTOM_KEY;
/**
* {@link Preference} key mapping to the String representation
* of a directory where persistent data can be stored. The directory is only used if the value
* to which {@link #IS_HISTORY_DIR_CUSTOM_KEY} maps is true.
*/
@NonNull static String HISTORY_DIR_KEY;
/**
* {@link ListPreference} key mapping to one of three String
* values: "0" (for {@code READ} mode), "1" (for {@code WRITE} mode), or "2" (for {@code ARITHMETIC}
* mode). The mapped String represent which {@code EditMode} is currently
* being used.
*/
@NonNull static String EDIT_MODE_KEY;
@NonNull static String EDIT_MODE_READ;
@NonNull static String EDIT_MODE_WRITE;
@NonNull static String EDIT_MODE_ARITHMETIC;
/**
* {@link ListPreference ListPreference} key mapping to either {@link
* #APP_THEME_DARK} or {@link #APP_THEME_LIGHT}, depending on which theme is currently
* being used.
*/
@NonNull static String APP_THEME_KEY;
/**
* One of the possible values that the {@link Preference Preference} to
* which {@link #APP_THEME_KEY} maps can be (the other being {@link #APP_THEME_LIGHT}).
*/
@NonNull static String APP_THEME_DARK;
/**
* One of the possible values that the {@link Preference Preference} to
* which {@link #APP_THEME_KEY} maps can be (the other being {@link #APP_THEME_DARK}).
*/
@NonNull static String APP_THEME_LIGHT;
/**
* {@link ListPreference ListPreference} key mapping to either {@link
* #NETWORK_SOURCE_WEB_SERVER} or {@link #NETWORK_SOURCE_BLUETOOTH_SERVER}, depending on
* which network source is currently being used.
*/
@NonNull static String NETWORK_SOURCE_KEY;
/**
* One of the possible values that the {@link Preference Preference} to
* which {@link #NETWORK_SOURCE_KEY} maps can be (the other being {@link
* #NETWORK_SOURCE_BLUETOOTH_SERVER}).
*/
@NonNull static String NETWORK_SOURCE_WEB_SERVER;
/**
* One of the possible values that the {@link Preference Preference} to
* which {@link #NETWORK_SOURCE_KEY} maps can be (the other being {@link
* #NETWORK_SOURCE_WEB_SERVER}).
*/
@NonNull static String NETWORK_SOURCE_BLUETOOTH_SERVER;
/**
* {@link Preference Preference} key mapping to the friendly name of the
* Bluetooth device being used (if enabled).
*/
@NonNull static String BLUETOOTH_DEVICE_NAME_KEY;
/**
* {@link Preference Preference} key mapping to the MAC address of the
* Bluetooth device being used (if enabled).
*/
@NonNull static String BLUETOOTH_DEVICE_ADDRESS_KEY;
@NonNull static String SPECIAL_KEYS_VISIBLE_KEY;
/**
* Maps special {@link Preference Preference} keys to their default values
* when the default values are impossible to know before runtime (e.g., the external cache
* directory, which {@link #IS_HISTORY_DIR_CUSTOM_KEY} maps to by default).
*/
@NonNull static Map<String, ?> DYNAMIC_PREF_DEFAULTS_MAP;
@NonNull static String IS_FIRST_TIME_KEY;
/**
* {@link Preference} key used to choose the Bluetooth device if Bluetooth communications
* are enabled.
*/
@NonNull static String CHOOSE_BLUETOOTH_DEVICE_KEY;
@NonNull static String SHOW_LINE_NUMBERS_KEY;
/**
* {@link Preference} key used for resetting preferences back to their default values.
*/
@NonNull static String RESTORE_DEFAULTS_KEY;
private Prefs() {}
static void initPrefs(@NonNull final Context context) {
final Resources r = context.getResources();
IS_HISTORY_DIR_CUSTOM_KEY = r.getString(R.string.pref_is_history_dir_custom);
HISTORY_DIR_KEY = r.getString(R.string.pref_history_dir);
EDIT_MODE_KEY = r.getString(R.string.pref_edit_mode);
EDIT_MODE_READ = r.getString(R.string.pref_edit_mode_read);
EDIT_MODE_WRITE = r.getString(R.string.pref_edit_mode_write);
EDIT_MODE_ARITHMETIC = r.getString(R.string.pref_edit_mode_arithmetic);
APP_THEME_KEY = r.getString(R.string.pref_app_theme);
APP_THEME_DARK = r.getString(R.string.pref_app_theme_dark);
APP_THEME_LIGHT = r.getString(R.string.pref_app_theme_light);
NETWORK_SOURCE_KEY = r.getString(R.string.pref_network_source);
NETWORK_SOURCE_WEB_SERVER = r.getString(R.string.pref_network_source_web);
NETWORK_SOURCE_BLUETOOTH_SERVER = r.getString(R.string.pref_network_source_bluetooth);
BLUETOOTH_DEVICE_NAME_KEY = r.getString(R.string.pref_bluetooth_device_name);
BLUETOOTH_DEVICE_ADDRESS_KEY = r.getString(R.string.pref_bluetooth_device_address);
SPECIAL_KEYS_VISIBLE_KEY = r.getString(R.string.pref_special_keys_visible);
IS_FIRST_TIME_KEY = r.getString(R.string.pref_is_first_time);
CHOOSE_BLUETOOTH_DEVICE_KEY = r.getString(R.string.pref_choose_bluetooth_device);
SHOW_LINE_NUMBERS_KEY = r.getString(R.string.pref_show_line_numbers);
RESTORE_DEFAULTS_KEY = r.getString(R.string.pref_restore_defaults);
DYNAMIC_PREF_DEFAULTS_MAP = mapDynamicPrefDefaults();
PreferenceManager.setDefaultValues(context, R.xml.preferences, true);
getPrefsEditor(context).commit();
if (isFirstTime(context)) {
restoreDyanmicPrefDefaultValues(context);
setSpecialKeysVisible(context, false);
setIsFirstTime(context, false);
}
}
/**
* Convenience for retrieving the app's default {@link SharedPreferences}.
* @param context The {@link Context} to use.
* @return The app's {@code SharedPreferences}.
*/
@NonNull public static SharedPreferences getPrefs(@NonNull final Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
/**
* Convenience for retrieving the {@code Editor} that can change the app's
* {@link SharedPreferences}.
* @param context The {@link Context} to use.
* @return The app's {@code SharedPreferences.Editor}.
*/
@NonNull public static SharedPreferences.Editor getPrefsEditor(@NonNull final Context context) {
return getPrefs(context).edit();
}
/**
* Initializes {@link #DYNAMIC_PREF_DEFAULTS_MAP} by mapping {@link
* Preference Preference} keys to their default values when the default
* values are impossible to know before runtime.
* @return a map of {@code Preference} keys to their dynamic default values.
*/
@NonNull private static Map<String, ?> mapDynamicPrefDefaults() {
return ImmutableMap.of(HISTORY_DIR_KEY, DeviceConstants.CACHE_DIR);
}
/**
* Restores the preferences that are impossible to know before runtime to their
* default values.
*/
static void restoreDyanmicPrefDefaultValues(@NonNull final Context context) {
SharedPreferences.Editor editor = getPrefsEditor(context);
for (Entry<String, ?> entry : DYNAMIC_PREF_DEFAULTS_MAP.entrySet()) {
if (entry.getValue() instanceof String) {
editor.putString(entry.getKey(), (String) entry.getValue());
} else if (entry.getValue() instanceof Boolean) {
editor.putBoolean(entry.getKey(), (Boolean) entry.getValue());
} else if (entry.getValue() instanceof Integer) {
editor.putInt(entry.getKey(), (Integer) entry.getValue());
} else if (entry.getValue() instanceof Float) {
editor.putFloat(entry.getKey(), (Float) entry.getValue());
} else if (entry.getValue() instanceof Long) {
editor.putLong(entry.getKey(), (Long) entry.getValue());
} else if (entry.getValue() instanceof Set) {
@SuppressWarnings("unchecked")
Set<String> set = (Set<String>) entry.getValue();
editor.putStringSet(entry.getKey(), set);
}
}
editor.commit();
}
public static String getBluetoothDeviceAddress(@NonNull final Context context) {
return getPrefs(context).getString(BLUETOOTH_DEVICE_ADDRESS_KEY, null);
}
public static String getBluetoothDeviceName(@NonNull final Context context) {
return getPrefs(context).getString(BLUETOOTH_DEVICE_NAME_KEY, null);
}
public static EditMode getEditMode(@NonNull final Context context) {
String editMode = getPrefs(context).getString(EDIT_MODE_KEY, null);
if (editMode.equals(EDIT_MODE_READ)) {
return EditMode.READ;
} else if (editMode.equals(EDIT_MODE_WRITE)) {
return EditMode.WRITE;
} else if (editMode.equals(EDIT_MODE_ARITHMETIC)) {
return EditMode.ARITHMETIC;
} else {
return null;
}
}
public static String getHistoryDir(@NonNull final Context context) {
return getPrefs(context).getString(HISTORY_DIR_KEY, null);
}
public static NetworkSource getNetworkSource(@NonNull final Context context) {
String source = getPrefs(context).getString(NETWORK_SOURCE_KEY, null);
if (source.equals(NETWORK_SOURCE_WEB_SERVER)) {
return NetworkSource.WEB_SERVER;
} else if (source.equals(NETWORK_SOURCE_BLUETOOTH_SERVER)) {
return NetworkSource.BLUETOOTH_SERVER;
} else {
return null;
}
}
public static boolean getShowLineNumbers(@NonNull final Context context) {
return getPrefs(context).getBoolean(SHOW_LINE_NUMBERS_KEY, false);
}
public static boolean getSpecialKeysVisible(@NonNull final Context context) {
return getPrefs(context).getBoolean(SPECIAL_KEYS_VISIBLE_KEY, false);
}
/**
* Returns the resource ID of the current app theme (either {@code ThemeLight} or
* {@code ThemeDark}.
* @return the current app theme's resource ID.
*/
@Nullable public static Theme getTheme(@NonNull final Context context) {
String theme = getPrefs(context).getString(APP_THEME_KEY, null);
if (Objects.equal(theme, APP_THEME_LIGHT)) {
return Theme.LIGHT;
} else if (Objects.equal(theme, APP_THEME_DARK)) {
return Theme.DARK;
} else {
return null;
}
}
public static boolean isBluetoothSource(@NonNull final Context context) {
return Objects.equal(getNetworkSource(context), NetworkSource.BLUETOOTH_SERVER);
}
private static boolean isFirstTime(@NonNull final Context context) {
return getPrefs(context).getBoolean(IS_FIRST_TIME_KEY, true);
}
public static boolean isHistoryDirCustom(@NonNull final Context context) {
return getPrefs(context).getBoolean(IS_HISTORY_DIR_CUSTOM_KEY, false);
}
public static boolean isWebSource(@NonNull final Context context) {
return Objects.equal(getNetworkSource(context), NetworkSource.WEB_SERVER);
}
public static void refreshTheme(Context context) {
setTheme(context, getTheme(context));
}
public static void setBluetoothDeviceAddress(Context context, String address) {
getPrefsEditor(context).putString(BLUETOOTH_DEVICE_ADDRESS_KEY, address).commit();
}
public static void setBluetoothDeviceName(Context context, String friendlyName) {
getPrefsEditor(context).putString(BLUETOOTH_DEVICE_NAME_KEY, friendlyName).commit();
}
public static void setEditMode(Context context, EditMode editMode) {
SharedPreferences.Editor editor = getPrefsEditor(context);
switch (editMode) {
case READ:
editor.putString(EDIT_MODE_KEY, EDIT_MODE_READ);
break;
case WRITE:
editor.putString(EDIT_MODE_KEY, EDIT_MODE_WRITE);
break;
case ARITHMETIC:
editor.putString(EDIT_MODE_KEY, EDIT_MODE_ARITHMETIC);
break;
}
editor.commit();
}
public static void setHistoryDir(Context context, String dir) {
getPrefsEditor(context).putString(HISTORY_DIR_KEY, dir).commit();
}
public static void setIsFirstTime(Context context, boolean isFirstTime) {
getPrefsEditor(context).putBoolean(IS_FIRST_TIME_KEY, isFirstTime).commit();
}
public static void setIsHistoryDirCustom(Context context, boolean custom) {
getPrefsEditor(context).putBoolean(IS_HISTORY_DIR_CUSTOM_KEY, custom).commit();
}
public static void setNetworkSource(Context context, NetworkSource source) {
SharedPreferences.Editor editor = getPrefsEditor(context);
switch (source) {
case WEB_SERVER:
editor.putString(NETWORK_SOURCE_KEY, NETWORK_SOURCE_WEB_SERVER);
break;
case BLUETOOTH_SERVER:
editor.putString(NETWORK_SOURCE_KEY, NETWORK_SOURCE_BLUETOOTH_SERVER);
break;
}
editor.commit();
}
public static void setShowLineNumbers(@NonNull final Context context, final boolean newShowLineNumbers) {
getPrefsEditor(context).putBoolean(SHOW_LINE_NUMBERS_KEY, newShowLineNumbers).commit();
}
public static void setSpecialKeysVisible(Context context, boolean visible) {
getPrefsEditor(context).putBoolean(SPECIAL_KEYS_VISIBLE_KEY, visible).commit();
}
public static void setTheme(Context context, Theme theme) {
SharedPreferences.Editor editor = getPrefsEditor(context);
switch (theme) {
case LIGHT:
editor.putString(APP_THEME_KEY, APP_THEME_LIGHT);
context.setTheme(R.style.ThemeLight);
break;
case DARK:
editor.putString(APP_THEME_KEY, APP_THEME_DARK);
context.setTheme(R.style.ThemeDark);
break;
}
editor.commit();
}
public enum EditMode {
READ, WRITE, ARITHMETIC
}
public enum Theme {
LIGHT, DARK
}
public enum NetworkSource {
WEB_SERVER, BLUETOOTH_SERVER
}
}